﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.Specialized;
using System.Threading;
using ajayumi.develop.CSharp.WinForm.Controls;

namespace ajayumi.Platform.WinForm.UserCtlPanel
{
    /// <summary>
    /// AsyncUserControl.cs 有异步方法的用户控件
    /// Author   : 黄乙冬
    /// Date     : 2011-09-30 
    /// Modify   : 2012-04-25
    /// Modif    : 2012-07-05
    /// </summary>
    [ToolboxItem(false)]
    public partial class AsyncUserControl1 : UserControl
    {
        #region Variables

        private delegate void WorkerEventHandler(AsyncOperation asyncOp);
        private UserStateDictionary m_UserStateToLifetime = null;
        private SpinningProgress m_Spg = null;

        #endregion

        #region Properties

        /// <summary>
        /// 异常对象
        /// </summary>
        protected Exception Error { get; private set; }

        public Dictionary<object, Action<AsyncOperation>> Workers { get; private set; }

        #endregion

        #region Constructor

        public AsyncUserControl1()
        {
            InitializeComponent();
            this.InitializeSpg();

            this.m_UserStateToLifetime = new UserStateDictionary();
            this.Workers = new Dictionary<object, Action<AsyncOperation>>();
            this.InitWorkers();
        }

        #endregion

        #region Events

        public AsyncCompletedEventHandler AsyncCompleted;
        protected virtual void RaiseAsyncCompleted(AsyncCompletedEventArgs e)
        {
            if (AsyncCompleted != null && !this.IsDisposed)
            { AsyncCompleted(this, e); }
        }

        #endregion
        
        /// <summary>
        /// 初始化工作任务集合
        /// </summary>
        protected virtual void InitWorkers()
        {
            return;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.AddSpgToParent();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            this.ChangeSpgLocation();
        }

        protected override void OnHandleDestroyed(EventArgs e)
        {
            this.CancelAsync();
            this.m_Spg.Dispose();
            base.OnHandleDestroyed(e);
        }

        /// <summary>
        /// 将控件添加到父容器中
        /// </summary>
        /// <param name="control"></param>
        private void AddControlToParent(Control control)
        {
            Control parentCon = this.Parent;
            if (parentCon != null)
            {
                parentCon.Controls.Add(control);
                this.m_Spg.BringToFront();
            }
        }

        #region SpinningProgress相关方法

        /// <summary>
        /// 初始化SpinningProgress
        /// </summary>
        private void InitializeSpg()
        {
            this.m_Spg = new SpinningProgress()
            {
                Size = new Size(50, 50),
                Visible = false
            };
        }
        /// <summary>
        /// 将SpinningProgress添加到父容器中
        /// </summary>
        private void AddSpgToParent()
        {
            this.AddControlToParent(this.m_Spg);
        }
        /// <summary>
        /// 改变SpinningProgress的位置
        /// </summary>
        private void ChangeSpgLocation()
        {
            int left = (this.Width - this.m_Spg.Width) / 2;
            int top = (this.Height - this.m_Spg.Height) / 2;
            this.m_Spg.Location = new Point(left, top);
        }

        #endregion

        #region RunWorkAsync

        protected void RunWorkAsync()
        {
            this.BeginWaiting();

            foreach (KeyValuePair<object, Action<AsyncOperation>> item in this.Workers)
            {
                this.DisplayDedugMsg(string.Format("{0} 对象：{1} 执行 DoWorkAsync 方法", DateTime.Now, item.Key));
                AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(item.Key);

                //m_UserStateToLifetime有可能会同时被多线程访问，在此需要lock进行同步处理
                lock (m_UserStateToLifetime.SyncRoot)
                {
                    if (m_UserStateToLifetime.Contains(item.Key))
                    {
                        throw new ArgumentException(
                            "userState parameter must be unique",
                            "userState");
                    }
                    m_UserStateToLifetime[item.Key] = asyncOp;
                }

                //异步开始任务
                WorkerEventHandler workerDelegate = new WorkerEventHandler(item.Value);
                workerDelegate.BeginInvoke(asyncOp,
                    (ar) =>
                    {
                        WorkerEventHandler worker = ar.AsyncState as WorkerEventHandler;
                        worker.EndInvoke(ar);

                        lock (m_UserStateToLifetime.SyncRoot)
                        {
                            m_UserStateToLifetime.Remove(asyncOp.UserSuppliedState);
                        }

                        this.WorkCompleted(this.Error, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);
                    },
                    workerDelegate);
            }

        }

        #endregion

        #region WorkComplete
        protected virtual void WorkCompleted(Exception exception, bool canceled, AsyncOperation asyncOp)
        {
            AsyncCompletedEventArgs arg = new AsyncCompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);
            //调用 PostOperationCompleted 方法来结束异步操作的生存期。
            //为某个特定任务调用此方法后，再调用其相应的 AsyncOperation 对象会引发异常。
            //通知指定的任务已经完成
            asyncOp.PostOperationCompleted(new SendOrPostCallback(state =>
            {
                AsyncCompletedEventArgs e = state as AsyncCompletedEventArgs;
                this.RaiseAsyncCompleted(e);

                //结束等待
                if (this.m_UserStateToLifetime.Count == 0)
                { this.EndWaiting(); }
            }), arg);

        }

        #endregion


        /// <summary>
        /// 开始等待
        /// </summary>
        protected virtual void BeginWaiting()
        {
            this.m_Spg.Visible = true;
            this.Enabled = false;
        }

        /// <summary>
        /// 结束等待
        /// </summary>
        protected virtual void EndWaiting()
        {
            this.m_Spg.Visible = false;
            this.Enabled = true;
        }


        #region CancelAsync
        /// <summary>
        /// 取消任务执行
        /// </summary>
        public void CancelAsync()
        {
            this.DisplayDedugMsg(string.Format("{0} 取消所有异步任务", DateTime.Now));
            this.m_UserStateToLifetime.Clear();
        }

        /// <summary>
        /// 取消指定userState的任务执行
        /// </summary>
        /// <param name="userState"></param>
        public void CancelAsync(object userState)
        {
            this.DisplayDedugMsg(string.Format("{0} 对象：{1} 执行 CancelAsync 方法", DateTime.Now, userState.ToString()));

            AsyncOperation asyncOp = this.GetAsyncOperation(userState);
            if (asyncOp != null)
            {
                lock (m_UserStateToLifetime.SyncRoot)
                {
                    m_UserStateToLifetime.Remove(userState);
                }
            }
        }
        #endregion


        /// <summary>
        /// 判断指定userState的任务是否已经被结束。返回值：true 已经结束； false 还没有结束
        /// </summary>
        /// <param name="userState"></param>
        /// <returns></returns>
        protected bool TaskCanceled(object userState)
        {
            return (m_UserStateToLifetime[userState] == null);
        }

        protected AsyncOperation GetAsyncOperation(object userState)
        { return (this.m_UserStateToLifetime[userState] as AsyncOperation); }

        /// <summary>
        /// 显示调式信息
        /// </summary>
        /// <param name="str">信息字符串</param>
        protected void DisplayDedugMsg(string str)
        { Console.WriteLine(str); }

        /// <summary>
        /// 更新用户界面
        /// </summary>
        /// <param name="action">委托方法</param>
        protected void UpdateUI(AsyncOperation asyncOp, Action action)
        {
            if (asyncOp != null && !this.IsDisposed && this.IsHandleCreated)
            {
                asyncOp.Post(new SendOrPostCallback(_ =>
                {
                    action.Invoke();
                }), null);
            }
        }

    }
}
